package com.lry.basic.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author:刘仁有
 * @desc:
 * @email:953506233@qq.com
 * @data:2019/9/11
 */
public class NIOServer {
    private int port;
    private Charset charset = Charset.forName("UTF-8");

    private ByteBuffer receiveBuf = ByteBuffer.allocate(1024);
    private ByteBuffer sendBuf = ByteBuffer.allocate(1024);
    private Map<String, SocketChannel> clientMap = new HashMap<>();

    private Selector selector;

    public NIOServer(int port){
        this.port = port;
        try {
            init();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void init() throws IOException {
        ServerSocketChannel server = ServerSocketChannel.open();
        server.configureBlocking(false);
        server.bind(new InetSocketAddress(port));
        selector = Selector.open();
        server.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务器启动，端口为：" + port);
    }

    public void listen(){
        while(true){
            try {
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                for (SelectionKey selectionKey:selectionKeys) {
                    handler(selectionKey);
                }
                selectionKeys.clear();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void handler(SelectionKey key) {
        try {
            if(key.isAcceptable()){
                ServerSocketChannel server = (ServerSocketChannel)key.channel();
                SocketChannel client = server.accept();
                client.configureBlocking(false);
                client.register(selector,SelectionKey.OP_READ);
                clientMap.put(client.toString(),client);
                System.out.println("客户端连接："+client.toString());
            }else if(key.isReadable()){
                SocketChannel client = (SocketChannel)key.channel();
                receiveBuf.clear();
                int read = client.read(receiveBuf);
                if(read>0){
                    receiveBuf.flip();
                    String receiveText = String.valueOf(charset.decode(receiveBuf));
                    System.out.println(client.toString() + ":" + receiveText);
                    dispatch(client, receiveText);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void dispatch(SocketChannel client, String receiveText) throws IOException {
        if(!clientMap.isEmpty()){
            for (Map.Entry<String, SocketChannel> entry : clientMap.entrySet()) {
                SocketChannel temp = entry.getValue();
                if (client.equals(temp)) {
                    sendBuf.clear();
                    sendBuf.put(charset.encode(client.toString() + ":" + receiveText));
                    sendBuf.flip();
                    temp.write(sendBuf);
                }
            }
        }
    }


    public static void main(String[] args) {
        NIOServer server = new NIOServer(9999);
        server.listen();
    }
}
